let Waiter = function () {
    let dfd = [],
        doneArr = [],
        failArr = [],
        slice = Array.prototype.slice,
        that = this;

    let Primise = function () {
        this.resolved = false;
        this.rejected = false;
    };
    Primise.prototype = {
        resolve() {
            this.resolved = true;
            if (!dfd.length)
                return;
            for (let i = dfd.length - 1; i >= 0; i--) {
                if (dfd[i] && !dfd[i].resolved || dfd[i].rejected) {
                    return;
                }
                dfd.splice(i, 1);
            }
            _exec(doneArr);
        },
        reject() {
            this.rejected = true;
            if (!dfd.length) {
                return;
            }
            dfd.splice(0);
            _exec(failArr);
        }
    };
    that.Deferred = function () {
        return new Primise();
    };
    function _exec(arr) {
        for (let i = 0; i < arr.length; i++) {
            try {
                arr[i] && arr[i]();
            }catch (e) {}
        }
    }
    that.when = function () {
        dfd = slice.call(arguments);
        for (let i = dfd.length-1; i >= 0; i--) {
            if (!dfd[i] || dfd[i].resolved || dfd[i].rejected || !(dfd[i] instanceof Primise)) {
                dfd.splice(i, 1);
            }
        }
        return that;
    };
    that.done = function () {
        doneArr = doneArr.concat(slice.call(arguments));
        return that;
    };
    that.fail = function () {
        failArr = failArr.concat(slice.call(arguments));
        return that;
    }
};

let waiter = new Waiter();
let first = function () {
    let dtd = waiter.Deferred();
    setTimeout(function () {
        console.log('first finish');
        dtd.resolve();
    }, 5000);
    return dtd;
}();
let second = function () {
    let dtd = waiter.Deferred();
    setTimeout(function () {
        console.log('second finish');
        dtd.resolve();
    }, 2000);
    return dtd;
}();
waiter.when(first, second).done(function () {
    console.log('all success')
}, function () {
    console.log('great')
}).fail(function () {
    console.log('fail');
});

let anotherWaiter = new Waiter();
let third = function () {
    let dtd = anotherWaiter.Deferred();
    setTimeout(function () {
        console.log('third finish');
        dtd.reject();
    }, 1000);
    return dtd;
}();
anotherWaiter.when(third).done(function () {
    console.log('another success')
}).fail(function () {
    console.log('another fail');
});